package com.anji.tug;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Logger;
import java.util.Set;

import javax.xml.bind.JAXBException;

import org.jgap.Chromosome;

public class TugManager {

	protected HashMap<String, Objective> objectives;
	private Logger logger;
	TugMonitor monitor;
	int onCount;
	
	public TugManager(HashMap<String, Objective> objectives) {
		this.objectives = objectives;
		this.onCount = objectives.size();
		monitor = new TugMonitor(objectives);
		monitor.showWindow();
	}
	
	public static TugManager createTugManagerFromObjectivesXml(String xmlFilePath) throws JAXBException {
		return new TugManager(ObjectivesLoader.descriptorListToObjectiveHash(ObjectivesLoader.getObjectives(xmlFilePath)));
	}
	
	protected void updateGoals() {
		for (Entry<String, Objective> entry : objectives.entrySet()) {
			Objective objective = entry.getValue();
			objective.updateGoal();
			info("TUG: Objective " + objective.name +" updated: " + objective.goal);
		}
		onCount = objectives.size();
	}

	public void updateObjectives(Map<Chromosome, HashMap<String, Float>> individualMetrics) {
        aggregateMetrics(individualMetrics);
        
        onCount = 0;
        
        for (Entry<String, Objective> entry : objectives.entrySet()) {
        	Objective objective = entry.getValue();
        	if (!objective.isOn) {
        		if (objective.avg < objective.goal) {
        			objective.isOn = true;
        			info("TUG: Average dropped for goal  +++> " 
        					+ objective.name 
        					+ " <+++ , turning back on."
        					+ "(rA:" 
            				+ objective.recencyAvg 
            				+ ", A:" 
            				+ objective.avg 
            				+ ", G:"
            				+ objective.goal 
            				+ ")"
            		);
        		}
        	}
        	
        	else if (objective.recencyAvg >= objective.goal && objective.avg >= objective.goal ) {
        		objective.isOn = false;
        		info("TUG: Goal met for  ---> " 
        				+ objective.name 
        				+ " <---  turning off. (rA:" 
        				+ objective.recencyAvg 
        				+ ", A:" 
        				+ objective.avg 
        				+ ", G:"
        				+ objective.goal 
        				+ ")"
        		);
        	}
        	
        	if (objective.isOn) onCount++;
        }
        
        if (0 == onCount) {
        	info("TUG: ### All goals met, updating...");
        	updateGoals();
        }
        
        if (null != monitor) monitor.update();
	}
	
	protected void aggregateMetrics(Map<Chromosome, HashMap<String, Float>> individualMetrics) {
		// Reset average for all objectives
		for (Entry<String, Objective> entry : objectives.entrySet()) entry.getValue().avg = 0;
		Set<Entry<Chromosome, HashMap<String, Float>>> set = individualMetrics.entrySet();
		int numChr = set.size();
		
		for (Entry<Chromosome, HashMap<String, Float>> entry : set) {
			HashMap<String, Float> metricList = entry.getValue();
			for (Entry<String, Float> metric : metricList.entrySet()) {
				Objective objective = objectives.get(metric.getKey());
				float value = metric.getValue();
				objective.avg += value / numChr;
				if (value > objective.record) objective.record = value;
			}
		}
		
		// Calculate recency averages
		for (Entry<String, Objective> entry : objectives.entrySet()) entry.getValue().updateRecencyAverage();
	}
	
	public Set<Entry<String, Objective>> getObjectivesSet() {return objectives.entrySet();}
	
	

	public void setLogger(Logger logger) {
		this.logger = logger;
	}
	
	private void info(String msg) {if (logger != null) logger.info(msg);}
	private void severe(String msg) {if (logger != null) logger.severe(msg);}
	
	public int getTotalNumObjectives() {return objectives.size();}
	public int getNumObjectivesOn() {return onCount;}
	
	/**
	 * @param args
	 * @throws JAXBException 
	 */
	public static void main(String[] args) throws JAXBException {
		TugManager m = TugManager.createTugManagerFromObjectivesXml("configs/tugObjectivesBase.xml");
		

	}

}
